package io.github.mengflyl.excel.report.viewer;

import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import io.github.mengfly.excel.report.Container;
import io.github.mengfly.excel.report.template.ContainerTreeNode;
import io.github.mengfly.excel.report.template.ReportTemplate;
import io.github.mengfly.excel.report.util.XmlUtil;
import lombok.Getter;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.plaf.FontUIResource;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;

@Getter
public class MainWindow {

    private File curTemplateFile;

    private JTextArea taTemplateInfo;
    private JPanel contentPanel;
    private ContainerViewer containerViewer;
    private JList<File> recentFileList;
    private RSyntaxTextArea rstaTemplate;
    private JScrollPane scrollViewer;
    private JCheckBox cbShowGridLine;
    private JCheckBox cbShowNumber;
    private JButton refreshCtrlEButton;
    private JButton openInDirButton;
    private JTextField textFieldWidth;
    private JTextField textFieldHeight;

    public MainWindow() {

        rstaTemplate.setSyntaxEditingStyle(RSyntaxTextArea.SYNTAX_STYLE_JAVA);
        rstaTemplate.setLineWrap(true);

        scrollViewer.getVerticalScrollBar().setUnitIncrement(40);

        initData();

        initListener();
    }


    private void initData() {
        recentFileList.setCellRenderer(new DefaultListCellRenderer() {
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                if (value instanceof File) {
                    File file = (File) value;
                    ((JLabel) component).setText(file.getName());
                }
                return component;
            }
        });
        textFieldWidth.setText(String.valueOf(containerViewer.getUnitWidth()));
        textFieldHeight.setText(String.valueOf(containerViewer.getUnitHeight()));
        refreshRecentFileData();
    }

    private void refreshRecentFileData() {
        recentFileList.setListData(ApplicationSetting.getRecentFiles().toArray(new File[0]));
        recentFileList.addNotify();
    }

    public void setTemplateFile(File file) {
        this.curTemplateFile = file;
        refresh(true);
    }

    private void initListener() {
        recentFileList.registerKeyboardAction(e -> {
            final File selectedValue = recentFileList.getSelectedValue();
            if (selectedValue != null) {
                final int optionResult = JOptionPane.showConfirmDialog(this.getContentPanel(), "是否打开删除 " +
                        selectedValue.getName(), "删除？", JOptionPane.YES_NO_OPTION);
                if (optionResult == JOptionPane.YES_OPTION) {
                    ApplicationSetting.removeRecentFile(selectedValue);
                    refreshRecentFileData();
                }
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), JComponent.WHEN_FOCUSED);

        recentFileList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() != 2) {
                    return;
                }
                final int i = recentFileList.locationToIndex(e.getPoint());
                if (i >= 0) {
                    final File selectedValue = recentFileList.getSelectedValue();
                    if (selectedValue != null && !selectedValue.equals(curTemplateFile)) {
                        setTemplateFile(selectedValue);
                    }
                }
            }
        });

        containerViewer.setOnContainerSelected(container -> {
            final ContainerTreeNode templateNode = container.getTemplateNode();
            if (templateNode != null) {
                final String str = XmlUtil.toStr(templateNode.getElement(), "UTF-8", true, true);
                rstaTemplate.setText(str);
            }
        });


        cbShowGridLine.addActionListener(e -> {
            containerViewer.setShowGridLine(cbShowGridLine.isSelected());
            scrollViewer.updateUI();
        });
        cbShowNumber.addActionListener(e -> {
            containerViewer.setShowCellNumber(cbShowNumber.isSelected());
            scrollViewer.updateUI();
        });
        scrollViewer.addMouseWheelListener(e -> {

            if (e.isControlDown()) {
                if (e.getWheelRotation() > 0) {
                    double newScore = containerViewer.getScale() * 0.9;
                    if (newScore >= ContainerViewer.minScale) {
                        containerViewer.setScale(newScore);
                        scrollViewer.updateUI();
                    }
                } else {
                    double newScore = containerViewer.getScale() * 1.1;
                    if (newScore <= ContainerViewer.maxScale) {
                        containerViewer.setScale(newScore);
                        scrollViewer.updateUI();
                    }
                }
            }
        });

        refreshCtrlEButton.addActionListener(e -> this.refresh(false));

        openInDirButton.addActionListener(e -> {
            if (curTemplateFile != null) {
                Desktop desktop = Desktop.getDesktop();
                try {
                    desktop.open(curTemplateFile.getParentFile());
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        });

        textFieldWidth.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    try {
                        final int width = (int) Double.parseDouble(textFieldWidth.getText());
                        if (width > 0) {
                            containerViewer.setUnitWidth(width);
                            scrollViewer.updateUI();
                        }
                    } catch (Exception err) {
                        textFieldWidth.setText(String.valueOf(containerViewer.getUnitWidth()));
                    }
                }
            }
        });

        textFieldHeight.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    try {
                        final int height = (int) Double.parseDouble(textFieldHeight.getText());
                        if (height > 0) {
                            containerViewer.setUnitHeight(height);
                            scrollViewer.updateUI();
                        }
                    } catch (Exception err) {
                        textFieldHeight.setText(String.valueOf(containerViewer.getUnitHeight()));
                    }
                }
            }
        });
    }

    public void refresh(boolean store) {
        if (this.curTemplateFile == null) {
            return;
        }
        try (FileInputStream stream = new FileInputStream(curTemplateFile)) {
            ReportTemplate reportTemplate = new ReportTemplate(stream);
            final Container render = reportTemplate.render(new PreviewDataContext());

            containerViewer.setContainer(render);
            scrollViewer.updateUI();
            final String name = reportTemplate.getName();
            final String author = reportTemplate.getAuthor();
            final String description = reportTemplate.getDescription();
            final Date createAt = reportTemplate.getCreateAt();

            String templateInfo = "模板名称: " + name + "\n" +
                    "作者: " + author + "\n" +
                    "创建时间: " + createAt + "\n" +
                    "描述: " + description + "\n"
                    + "文件位置: " + curTemplateFile.getAbsolutePath();

            this.taTemplateInfo.setText(templateInfo);

            if (store) {
                ApplicationSetting.addRecentFile(curTemplateFile);
                refreshRecentFileData();
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(contentPanel,
                    "无法加载模板文件:" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        contentPanel = new JPanel();
        contentPanel.setLayout(new BorderLayout(0, 0));
        contentPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        contentPanel.add(panel1, BorderLayout.CENTER);
        scrollViewer = new JScrollPane();
        panel1.add(scrollViewer, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        containerViewer = new ContainerViewer();
        scrollViewer.setViewportView(containerViewer);
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1));
        panel2.setBackground(new Color(-394241));
        panel2.setPreferredSize(new Dimension(200, 54));
        contentPanel.add(panel2, BorderLayout.WEST);
        recentFileList = new JList();
        recentFileList.setPreferredSize(new Dimension(200, 0));
        panel2.add(recentFileList, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_WANT_GROW, null, new Dimension(150, 50), null, 0, false));
        final JLabel label1 = new JLabel();
        Font label1Font = this.$$$getFont$$$(null, Font.BOLD, 16, label1.getFont());
        if (label1Font != null) label1.setFont(label1Font);
        label1.setText("Recent Templates");
        panel2.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JScrollPane scrollPane1 = new JScrollPane();
        scrollPane1.setPreferredSize(new Dimension(200, 100));
        contentPanel.add(scrollPane1, BorderLayout.SOUTH);
        rstaTemplate = new RSyntaxTextArea();
        rstaTemplate.setEditable(false);
        scrollPane1.setViewportView(rstaTemplate);
        final JPanel panel3 = new JPanel();
        panel3.setLayout(new GridLayoutManager(10, 1, new Insets(0, 0, 0, 0), -1, -1));
        contentPanel.add(panel3, BorderLayout.EAST);
        panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        final JLabel label2 = new JLabel();
        Font label2Font = this.$$$getFont$$$(null, Font.BOLD, 18, label2.getFont());
        if (label2Font != null) label2.setFont(label2Font);
        label2.setText("Template Properties");
        panel3.add(label2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        panel3.add(spacer1, new GridConstraints(9, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        taTemplateInfo = new JTextArea();
        taTemplateInfo.setEditable(false);
        taTemplateInfo.setLineWrap(true);
        taTemplateInfo.setMargin(new Insets(0, 0, 10, 0));
        taTemplateInfo.setWrapStyleWord(true);
        panel3.add(taTemplateInfo, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JPanel panel4 = new JPanel();
        panel4.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        panel3.add(panel4, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        cbShowGridLine = new JCheckBox();
        cbShowGridLine.setSelected(false);
        cbShowGridLine.setText("显示网格线");
        panel4.add(cbShowGridLine, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        cbShowNumber = new JCheckBox();
        cbShowNumber.setSelected(true);
        cbShowNumber.setText("显示网格编号");
        panel3.add(cbShowNumber, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label3 = new JLabel();
        Font label3Font = this.$$$getFont$$$(null, Font.BOLD, 18, label3.getFont());
        if (label3Font != null) label3.setFont(label3Font);
        label3.setText("View Properties");
        panel3.add(label3, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer();
        panel3.add(spacer2, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        refreshCtrlEButton = new JButton();
        refreshCtrlEButton.setText("Refresh (Ctrl+E)");
        panel3.add(refreshCtrlEButton, new GridConstraints(7, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        openInDirButton = new JButton();
        openInDirButton.setText("Open In Dir");
        panel3.add(openInDirButton, new GridConstraints(8, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel5 = new JPanel();
        panel5.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel3.add(panel5, new GridConstraints(6, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label4 = new JLabel();
        label4.setText("单元格宽度 ：");
        panel5.add(label4, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        textFieldWidth = new JTextField();
        textFieldWidth.setText("");
        panel5.add(textFieldWidth, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(60, -1), null, 0, false));
        final JLabel label5 = new JLabel();
        label5.setText("单元格高度 ：");
        panel5.add(label5, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        textFieldHeight = new JTextField();
        panel5.add(textFieldHeight, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(60, -1), null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
        if (currentFont == null) return null;
        String resultName;
        if (fontName == null) {
            resultName = currentFont.getName();
        } else {
            Font testFont = new Font(fontName, Font.PLAIN, 10);
            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
                resultName = fontName;
            } else {
                resultName = currentFont.getName();
            }
        }
        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return contentPanel;
    }

}
